package com.ruoyi.common.utils.html

import com.ruoyi.common.utils.MyStringUtils


/**
 * 转义和反转义工具类
 *
 * @author ruoyi
 */
object EscapeUtil {
    const val RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"
    private val TEXT = arrayOfNulls<CharArray>(64)

    init {
        for (i in 0..63) {
            TEXT[i] = charArrayOf(i.toChar())
        }

        // special HTML characters
        TEXT['\''.code] = "&#039;".toCharArray() // 单引号
        TEXT['"'.code] = "&#34;".toCharArray() // 双引号
        TEXT['&'.code] = "&#38;".toCharArray() // &符
        TEXT['<'.code] = "&#60;".toCharArray() // 小于号
        TEXT['>'.code] = "&#62;".toCharArray() // 大于号
    }

    /**
     * 转义文本中的HTML字符为安全的字符
     *
     * @param text 被转义的文本
     * @return 转义后的文本
     */
    fun escape(text: String): String {
        return encode(text)
    }

    /**
     * 还原被转义的HTML特殊字符
     *
     * @param content 包含转义符的HTML内容
     * @return 转换后的字符串
     */
    fun unescape(content: String): String {
        return decode(content)
    }

    /**
     * 清除所有HTML标签，但是不删除标签内的内容
     *
     * @param content 文本
     * @return 清除标签后的文本
     */
    fun clean(content: String?): String? {
        return HTMLFilter().filter(content)
    }

    /**
     * Escape编码
     *
     * @param text 被编码的文本
     * @return 编码后的字符
     */
    private fun encode(text: String): String {
        if (MyStringUtils.isEmpty(text)) {
            return org.apache.commons.lang3.StringUtils.EMPTY
        }
        val tmp = StringBuilder(text.length * 6)
        var c: Char
        for (element in text) {
            c = element
            if (c.code < 256) {
                tmp.append("%")
                if (c.code < 16) {
                    tmp.append("0")
                }
                tmp.append(c.code.toString(16))
            } else {
                tmp.append("%u")
                if (c.code <= 0xfff) {
                    // issue#I49JU8@Gitee
                    tmp.append("0")
                }
                tmp.append(c.code.toString(16))
            }
        }
        return tmp.toString()
    }

    /**
     * Escape解码
     *
     * @param content 被转义的内容
     * @return 解码后的字符串
     */
    fun decode(content: String): String {
        if (MyStringUtils.isEmpty(content)) {
            return content
        }
        val tmp = StringBuilder(content.length)
        var lastPos = 0
        var pos = 0
        var ch: Char
        while (lastPos < content.length) {
            pos = content.indexOf("%", lastPos)
            if (pos == lastPos) {
                if (content[pos + 1] == 'u') {
                    ch = content.substring(pos + 2, pos + 6).toInt(16).toChar()
                    tmp.append(ch)
                    lastPos = pos + 6
                } else {
                    ch = content.substring(pos + 1, pos + 3).toInt(16).toChar()
                    tmp.append(ch)
                    lastPos = pos + 3
                }
            } else {
                lastPos = if (pos == -1) {
                    tmp.append(content.substring(lastPos))
                    content.length
                } else {
                    tmp.append(content.substring(lastPos, pos))
                    pos
                }
            }
        }
        return tmp.toString()
    }

    @JvmStatic
    fun main(args: Array<String>) {
        val html = "<script>alert(1);</script>"
        val escape = escape(html)
        // String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
        // String html = "<123";
        // String html = "123>";
        println("clean: " + clean(html))
        println("escape: $escape")
        println("unescape: " + unescape(escape))
    }
}
